/* { dg-do compile } */
// TODO: remove need for -fanalyzer-checker=taint here:
// TODO: remove need for --param=analyzer-max-svalue-depth=25 here:
/* { dg-options "-fanalyzer -fanalyzer-checker=taint --param=analyzer-max-svalue-depth=25" } */
/* { dg-require-effective-target analyzer } */

/* See notes in this header.  */
#include "taint-CVE-2011-0521.h"

/* Adapted from dvb_ca_ioctl in drivers/media/dvb/ttpci/av7110_ca.c and
   dvb_usercopy in drivers/media/dvb/dvb-core/dvbdev.c

   Further simplified from -4; avoid parg and the cast to char[128].  */

int test_1(struct file *file, unsigned int cmd, unsigned long arg)
{
	ca_slot_info_t sbuf;

	if (copy_from_user(&sbuf, (void __user *)arg, sizeof(sbuf)) != 0)
		return -1;

	{
		struct dvb_device *dvbdev = file->private_data;
		struct av7110 *av7110 = dvbdev->priv;

		/* case CA_GET_SLOT_INFO:  */
		ca_slot_info_t *info= &sbuf;

		__analyzer_dump_state ("taint", info->num); /* { dg-warning "tainted" } */

		if (info->num < 0 || info->num > 1)
			return -EINVAL;

		__analyzer_dump_state ("taint", info->num); /* { dg-warning "stop" } */

		av7110->ci_slot[info->num].num = info->num;
		av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ?
							CA_CI_LINK : CA_CI;
		memcpy(info, &av7110->ci_slot[info->num], sizeof(ca_slot_info_t)); /* { dg-bogus "use of attacker-controlled value in array lookup without bounds checking" "" { xfail *-*-* } } */
		// FIXME: why the above false +ve?
	}

	copy_to_user((void __user *)arg, &sbuf, sizeof(sbuf));

	return 0;
}
